#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "log.hpp"
#include <cstring>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <wait.h>
#include "lockGuard.hpp"
#include "Task.hpp"
#include "Thread.hpp"
#include "ThreadPool.hpp"
#include <unordered_map>
#include <memory>
// v1:单进程循环版本
static void service(int fd, std::string ip, const int16_t port)
{
    char buffer[256];
    while (true)
    {
        ssize_t s = read(fd, buffer, sizeof buffer - 1);
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << ip << ":" << port << "# " << buffer << std::endl;
        }
        else if (s == 0) // 对端关闭连接
        {
            logMessage(NORMAL, "%s:%d shutdown, me too!", ip.c_str(), port);
            break;
        }
        else
        { //
            logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        write(fd, buffer, strlen(buffer));
    }
}


static void dictOnline(int sock, const std::string &clientip,
                   const uint16_t &clientport, const std::string &thread_name)
{
    // echo server
    //  同时在线10人
    //  所以，我们一般服务器进程业务处理，如果是从连上，到断开，要一直保持这个链接, 长连接
    //  后面有其他方案！
    char buffer[1024];
    static std::unordered_map<std::string, std::string> dict = {
        {"apple", "苹果"},
        {"bite", "比特"},
        {"banana", "香蕉"},
        {"hard", "好难啊"}
    };
    // read && write 可以直接被使用！
    ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
    if (s > 0)
    {
        buffer[s] = 0; // 将发过来的数据当做字符串
        std::cout << thread_name << "|" << clientip << ":" << clientport << "# " << buffer << std::endl;
        std::string message;
        auto iter = dict.find(buffer);
        if(iter == dict.end()) message = "我不知道...";
        else message = iter->second;
        write(sock, message.c_str(), message.size());
    }
    else if (s == 0) // 对端关闭连接
    {
        logMessage(NORMAL, "%s:%d shutdown, me too!", clientip.c_str(), clientport);
    }
    else
    { //
        logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
    }

    close(sock);
}
//----v3:多线程版
class threadData
{
public:
    int _sock;
    std::string _ip;
    uint16_t _port;
};


class TcpServer
{
public:
    TcpServer(uint16_t port, std::string ip = "")
        : _port(port), _ip(ip), _listensock(-1)
    {
    }

    static void *threadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        threadData *td = static_cast<threadData *>(args);
        service(td->_sock, td->_ip, td->_port);
        delete td;

        return nullptr;
    }
    void initServer()
    {
        // 1. 创建socket -- 进程和文件
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logMessage(FATAL, "create socket error, %d:%s", errno, strerror(errno));
            exit(2);
        }

        logMessage(NORMAL, "create socket success, listensock: %d", _listensock);

        // 2. bind -- 文件 + 网络

        struct sockaddr_in local;
        bzero(&local, sizeof local);
        socklen_t len = sizeof local;
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        if (bind(_listensock, (sockaddr *)&local, len) < 0)
        {
            logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }
        // 3. 因为TCP是面向连接的，当我们正式通信的时候，需要先建立连接

        if (listen(_listensock, 5) < 0)
        {
            logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }

    void start()
    {
        ///*--v1:--*/signal(SIGCHLD,SIG_IGN);

        while (true)
        {
            // 4. 获取连接
            struct sockaddr_in src;
            socklen_t len = sizeof src;
            int servicesock = accept(_listensock, (sockaddr *)&src, &len);

            if (servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }

            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);

            logMessage(NORMAL, "link success, servicesock: %d | %s : %d |\n",
                       servicesock, client_ip.c_str(), client_port);

            ///*--v4--:线程池版本*/
            Task t(servicesock, client_ip, client_port, dictOnline);
            _threadpool_ptr->pushTask(t);


            ///*--v3--:多线程版本*/
            // threadData *td = new threadData();
            // td->_sock = servicesock;
            // td->_ip = client_ip;
            // td->_port = client_port;
            // pthread_t tid;
            // pthread_create(&tid, nullptr, threadRoutine, td);
            // close(servicesock);
            ///*--v2.1--:多进程版本*/
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     close(_listensock);
            //     if(fork()>0)
            //         exit(0);
            //     //孤儿进程执行
            //     service(servicesock, client_ip, client_port);
            //     exit(0);
            // }
            // waitpid(id,nullptr,0);
            // close(servicesock);

            ///*--v1:--*/
            // pid_t id = fork();
            // assert(id!=-1);
            // if(id==0)
            // {
            //     close(_listensock);
            //     service(servicesock,client_ip,client_port);
            //     exit(0);
            // }

            // close(servicesock);
        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
    std::unique_ptr<ThreadPool<Task>> _threadpool_ptr;
};